package com.mk.web.io.file.server.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * Created by WangChen on 2018/12/17 14:32.
 */
public class NioServer {

    public static void main(String [] args){
        try {
            // Selector: multiplexor of SelectableChannel objects
            Selector selector = Selector.open(); // selector is open here

            //
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress("localhost", 9999));

            // Adjusts this channel's blocking mode
            serverSocketChannel.configureBlocking(false);

            int ops = serverSocketChannel.validOps();
            SelectionKey selectKy = serverSocketChannel.register(selector, ops, null);
            //serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            // Infinite loop..
            // Keep server running
            while (true) {
                System.out.println("NioServer start...");
                // Selects a set of keys whose corresponding channels are ready for I/O operations
                // 阻塞方法，当至少一个通道被选中，此方法返回。
                // 通道是否选择，由注册到多路复用器中的通道标记决定。
//                int select = selector.select();
                System.out.println("select: " + selector.select());

                // token representing the registration of a SelectableChannel with a Selector
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> selectedIterator = selectedKeys.iterator();

                while (selectedIterator.hasNext()) {
                    SelectionKey myKey = selectedIterator.next();

                    // Tests whether this key's channel is ready to accept a new socket connection
                    if (myKey.isAcceptable()) {
                        SocketChannel socketClient = serverSocketChannel.accept();

                        // Adjusts this channel's blocking mode to false
                        socketClient.configureBlocking(false);

                        // Operation-set bit for read operations
                        socketClient.register(selector, SelectionKey.OP_READ);
                        System.out.println("Connection Accepted: " + socketClient.getLocalAddress() + "\n");

                        // Tests whether this key's channel is ready for reading
                    } else if (myKey.isReadable()) {

                        SocketChannel socketClient = (SocketChannel) myKey.channel();
                        ByteBuffer byteBufferuffer = ByteBuffer.allocate(256);
                        socketClient.read(byteBufferuffer);
                        String result = new String(byteBufferuffer.array()).trim();

                        System.out.println("Message received: " + result);

                        if (result.equals("Crunchify")) {
                            socketClient.close();
                            System.out.println("\nIt's time to close connection as we got last company name 'Crunchify'");
                            System.out.println("\nServer will keep running. Try running client again to establish new connection");
                        }
                    }
                    selectedIterator.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
